package team119;

import battlecode.common.Clock;
import battlecode.common.Direction;
import battlecode.common.GameActionException;
import battlecode.common.GameConstants;
import battlecode.common.MapLocation;
import battlecode.common.Robot;
import battlecode.common.RobotController;
import battlecode.common.RobotType;
import battlecode.common.TerrainTile;

public  class SoldierMovement {
	final private static Boolean OUTPUT_DEBUG=true;
	private static MapLocation nearestEncampment = null;
	
	
	public static void PerformMovement(RobotController rc,BOTInstanceVariables instanceVariables) throws GameActionException
	{
		instanceVariables.AddLocation(rc.getLocation());
		Direction dir=null;
		
		
		Direction battleDir=DirectionTowardTeamatesInBattle(rc);
		if(battleDir!=null)//If there is an enemy nearby, pursue them
		{
			if(OUTPUT_DEBUG)System.out.println("Going towards the enemy: "+battleDir);
			dir=battleDir;
		}
		
		try {
			if (rc.senseEncampmentSquare(rc.getLocation())) {
				int numEnc = rc.readBroadcast(2545 % GameConstants.BROADCAST_MAX_CHANNELS);
				rc.broadcast(2545 % GameConstants.BROADCAST_MAX_CHANNELS, numEnc+1);
				if (numEnc > 3 && numEnc % 2 == 0) {
					rc.captureEncampment(RobotType.GENERATOR);
				} else {
					rc.captureEncampment(RobotType.SUPPLIER);
				}
				return;//Can't move after capturing
			}
		} catch (Exception e) {
			//do nothing.
		}
		
		Robot[] nearbyAllies = rc.senseNearbyGameObjects(Robot.class,20,rc.getTeam());
		if ( dir == null && 
				(nearbyAllies.length < 9 || rc.readBroadcast(2550 % GameConstants.BROADCAST_MAX_CHANNELS)>0) ) {
			if (nearestEncampment == null) {
				nearestEncampment = GetNearestEncampment(rc);
			}
			
			Direction encampDir = AimAtLocation(rc, nearestEncampment, instanceVariables);
			if(encampDir!=Direction.OMNI)
			{
				dir=encampDir;
				if(OUTPUT_DEBUG)System.out.println("Going towards nearestEncampment "+dir);
			}
			
		}
		
		if(dir==null || 
				((rc.readBroadcast(2550 % GameConstants.BROADCAST_MAX_CHANNELS) > 0 || instanceVariables.isAttack) 
						))//If no other target has been acquired then go towards the enemy HQ
		{
			dir= AimAtEnemyHQ(rc,instanceVariables);
			instanceVariables.isAttack = true;
		}
		
		
		if(OUTPUT_DEBUG)System.out.println("About to check for stuck case");
		if(StuckCase(rc,rc.getLocation().add(dir)) || dir == Direction.NONE || dir == Direction.OMNI || !rc.canMove(dir)) //Check if they are surrounded by mines and people and cannot move
		{
			if(OUTPUT_DEBUG)System.out.println("Is a stuck case");
			dir=FindNearestMineDirection(rc,dir);
		}
		
		
		HelperMethods.SafeMove(dir, rc);
	}
	
	private static MapLocation GetNearestEncampment(RobotController rc) {
		MapLocation ml = null;
		int x = 0;
		int y = 0;
		try {
			x = rc.readBroadcast(2540 % GameConstants.BROADCAST_MAX_CHANNELS);
			y = rc.readBroadcast(2541 % GameConstants.BROADCAST_MAX_CHANNELS);
			if (x > 0 | y > 0) {
				rc.setIndicatorString(1, "ReadBroadcast: " + x + ", " + y + ")");
				ml = new MapLocation(x,y);
				return ml;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		
		Direction dirHQ = rc.senseHQLocation().directionTo(rc.senseEnemyHQLocation());
		ml = rc.senseHQLocation().add(dirHQ).add(dirHQ).add(dirHQ).add(dirHQ).add(dirHQ);
		
		MapLocation[] all = rc.senseAllEncampmentSquares();
		int dist = 1000000;
		
		for (int i = 0; i < all.length; i++) {
			if (rc.getLocation().distanceSquaredTo(all[i]) < dist) {
				ml = all[i];
				dist = rc.getLocation().distanceSquaredTo(all[i]);
			}
		}
		
		if(rc.getLocation().distanceSquaredTo(rc.senseEnemyHQLocation())< rc.getLocation().distanceSquaredTo(ml))
				return rc.senseEnemyHQLocation();
		return ml;
	}
	
	private static Direction DirectionTowardTeamatesInBattle(RobotController rc) throws GameActionException
	{
		Robot[] enemyRobots = rc.senseNearbyGameObjects(Robot.class,50,rc.getTeam().opponent());
		if(enemyRobots.length!=0) //Enemies Spotted
		{
			int closestDist = 50;
			MapLocation closestEnemy=null;
			for (int i=0;i<enemyRobots.length;i++){
				Robot arobot = enemyRobots[i];
				try {
					battlecode.common.RobotInfo arobotInfo = rc.senseRobotInfo(arobot);
					int dist = arobotInfo.location.distanceSquaredTo(rc.getLocation());
					if (dist<closestDist)
					{
						closestDist = dist;
						closestEnemy = arobotInfo.location;
					}
				} catch (Exception ex) {
					//do nothing (aka - move on to next enemy.
				}
			}
			if(closestEnemy==null)
				return null;
			Direction dir = rc.getLocation().directionTo(closestEnemy);
			return dir;
		}
		return null;
		
	}
	
	private static Direction FindNearestMineDirection(RobotController rc,Direction dir)
	{
		Direction startingDir=dir;
		int x=0;
		do
		{
			dir=NextDir(dir,true);
			x++;
		}
		while(rc.senseMine(rc.getLocation().add(dir))==null &&x<8);
		
		if(rc.senseMine(rc.getLocation().add(dir))==null)
			return startingDir;
		return dir;
	}
	
	private static  Boolean StuckCase(RobotController rc,MapLocation locationToMove) throws GameActionException
	{
		Robot[] teamRobots = rc.senseNearbyGameObjects(Robot.class,1,rc.getTeam());
		for(Robot bot : teamRobots)
		{
			try {
				battlecode.common.RobotInfo botInfo=rc.senseRobotInfo(bot);
				if(botInfo.location==locationToMove)
				{
					return true;
				}
			} catch (Exception ex) {
				
			}
		}
		return false;
	}
	
	private static Direction NextDir(Direction dir, boolean isClockwise) 
	{
		if (isClockwise) {
			if (dir == Direction.NORTH) {
				return Direction.NORTH_EAST;
			} else if (dir == Direction.NORTH_WEST) {
				return Direction.NORTH;
			} else if (dir == Direction.WEST) {
				return Direction.NORTH_WEST;
			} else if (dir == Direction.SOUTH_WEST) {
				return Direction.WEST;
			} else if (dir == Direction.SOUTH) {
				return Direction.SOUTH_WEST;
			} else if (dir == Direction.SOUTH_EAST) {
				return Direction.SOUTH;
			} else if (dir == Direction.EAST) {
				return Direction.SOUTH_EAST;
			} else if (dir == Direction.NORTH_EAST) {
				return Direction.EAST;
			}
		} else {
			if (dir == Direction.EAST) {
				return Direction.NORTH_EAST;
			} else if (dir == Direction.NORTH_EAST) {
				return Direction.NORTH;
			} else if (dir == Direction.NORTH) {
				return Direction.NORTH_WEST;
			} else if (dir == Direction.NORTH_WEST) {
				return Direction.WEST;
			} else if (dir == Direction.WEST) {
				return Direction.SOUTH_WEST;
			} else if (dir == Direction.SOUTH_WEST) {
				return Direction.SOUTH;
			} else if (dir == Direction.SOUTH) {
				return Direction.SOUTH_EAST;
			} else if (dir == Direction.SOUTH_EAST) {
				return Direction.EAST;
			}
		}
		
		return dir;
	}
	
	private static Direction AimAtLocation(RobotController rc,MapLocation loc,BOTInstanceVariables instanceVariables)
	{
		Direction dir = rc.getLocation().directionTo(loc);
		Direction initialDir=dir;
		if (dir == Direction.NONE || dir == Direction.OMNI) {
			return dir;
		}
		
		while (!(rc.senseMine(rc.getLocation().add(dir))==null && rc.canMove(dir))  )
		{
			dir = NextDir(dir, true);
			if(dir==initialDir)
				return dir;// its gone all the way around
			
		}
	
		return dir;
	}
	
	private static Direction AimAtEnemyHQ(RobotController rc,BOTInstanceVariables bic) {
		
		return AimAtLocation(rc,rc.senseEnemyHQLocation(),bic);
	}

}
